# Import required libraries
import pandas as pd
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score
import joblib
import math

# Set random seed for reproducibility
np.random.seed(123)

# Read the data
data = pd.read_excel("CT_1_Transformed.xlsx")

# Prepare the data
X = data.drop(['Sample', 'Contents'], axis=1)
y = data['Contents']

# Scale the features
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)

# Random Forest Model
print("\nTraining Random Forest Model...")

# Define parameter grid for RF
rf_param_grid = {
    'n_estimators': [500],
    'max_features': [int(math.sqrt(X.shape[1])), 
                    int(X.shape[1]/3), 
                    int(X.shape[1]/2)],
    'min_samples_split': [2, 5],
    'min_samples_leaf': [1, 2]
}

# Create and train Random Forest model with grid search
rf = RandomForestRegressor(random_state=123, n_jobs=-1)
rf_cv = GridSearchCV(rf, rf_param_grid, cv=5, n_jobs=-1, verbose=2, 
                    scoring='neg_mean_squared_error')
rf_cv.fit(X_scaled, y)

# Get RF predictions and metrics
rf_predictions = rf_cv.predict(X_scaled)
rf_rmse = np.sqrt(mean_squared_error(y, rf_predictions))
rf_r2 = r2_score(y, rf_predictions)

# Get feature importance for RF
rf_feature_importance = pd.DataFrame({
    'feature': X.columns,
    'importance': rf_cv.best_estimator_.feature_importances_
})
rf_top_10 = rf_feature_importance.nlargest(10, 'importance')

# SVM Model
print("\nTraining SVM Model...")

# Define parameter grid for SVM
svm_param_grid = {
    'C': [0.1, 1, 10],
    'gamma': [0.001, 0.01, 0.1]
}

# Create and train SVM model with grid search
svm = SVR(kernel='rbf')
svm_cv = GridSearchCV(svm, svm_param_grid, cv=5, n_jobs=-1, verbose=2, 
                     scoring='neg_mean_squared_error')
svm_cv.fit(X_scaled, y)

# Get SVM predictions and metrics
svm_predictions = svm_cv.predict(X_scaled)
svm_rmse = np.sqrt(mean_squared_error(y, svm_predictions))
svm_r2 = r2_score(y, svm_predictions)

# Print Results
print("\nRandom Forest Results:")
print("Best parameters:", rf_cv.best_params_)
print("Cross-validation results:")
print(pd.DataFrame(rf_cv.cv_results_)[['params', 'mean_test_score', 'std_test_score']])
print(f"Final RMSE: {rf_rmse:.4f}")
print(f"Final R-squared: {rf_r2:.4f}")

print("\nSVM Results:")
print("Best parameters:", svm_cv.best_params_)
print("Cross-validation results:")
print(pd.DataFrame(svm_cv.cv_results_)[['params', 'mean_test_score', 'std_test_score']])
print(f"Final RMSE: {svm_rmse:.4f}")
print(f"Final R-squared: {svm_r2:.4f}")

# Model comparison
results_comparison = pd.DataFrame({
    'Model': ['Random Forest', 'SVM'],
    'RMSE': [rf_rmse, svm_rmse],
    'R_squared': [rf_r2, svm_r2]
})

print("\nModel Comparison:")
print(results_comparison)

print("\nTop 10 Most Important Features (Random Forest):")
print(rf_top_10)

# Save models
# joblib.dump(rf_cv, 'rf_model.joblib')
# joblib.dump(svm_cv, 'svm_model.joblib')
# joblib.dump(scaler, 'scaler.joblib')